package com.huoshan.im.server.action;

import com.alibaba.fastjson.JSONObject;
import com.huoshan.im.server.ContextNaming;
import com.huoshan.im.server.SessionHolder;
import com.huoshan.im.server.action.support.JsonActionSupport;
import com.huoshan.im.server.config.ConfigHolder;
import com.huoshan.im.server.dto.UserDto;
import com.huoshan.im.server.dto.in.LoginUser;
import com.huoshan.im.server.dto.out.MessageIdTxt;
import com.huoshan.im.server.dto.out.MessageTxt;
import com.huoshan.im.server.enums.ErrorCode;
import com.huoshan.im.server.messaging.MessageId;
import com.huoshan.im.server.service.UserService;
import com.qy.esports.common.dto.UserInfoJwtDto;
import com.qy.esports.common.utils.JsonUtils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtException;
import lombok.extern.slf4j.Slf4j;
import online.chazi.bootplus.commons.utils.JwtUtils;
import online.chazi.netkit.annotation.Inject;
import online.chazi.netkit.messaging.Message;
import org.springframework.beans.BeanUtils;

/**
 * 说明：处理客户端登录
 * Created by 火山九日 on 2020-04-26 10:02
 */
@Slf4j
@Inject
public class LoginAction extends JsonActionSupport<LoginUser> {

    private UserService userService;

    public void execute(LoginUser loginUser) {

        userService.userSayHi();

        try {

            if (loginUser != null) {

                log.info("用户登陆：{}", JSONObject.toJSONString(loginUser));

                Claims claims = JwtUtils.parseJwt(loginUser.getTo火山九日(), ConfigHolder.getSettingConfig().getJwtKey());
                UserInfoJwtDto context = JsonUtils.parse(claims.getSubject(), UserInfoJwtDto.class);

                if (context != null && context.getUserId().intValue() == loginUser.getUserId()) {

                    //保存用户信息
                    setAttribute(ContextNaming.SESSION_USER_ID, loginUser.getUserId());

                    //设置版本号
                    setAttribute(ContextNaming.SESSION_VERSION, loginUser.getAppVersion());

                    //登录设备号
                    setAttribute(ContextNaming.SESSION_DEVICE_ID, loginUser.getDeviceId());

                    final long currentTimeMillis = System.currentTimeMillis();

                    //这里先写死APP
                    setAttribute(ContextNaming.SESSION_CLIENT_TYPE, UserDto.APP);

                    //登录时间
                    setAttribute(ContextNaming.SESSION_LOGIN_TIMESTAMP, currentTimeMillis);

                    log.info("登录成功~~~,userId={},channel.id={}", loginUser.getUserId(), getSession().getChannel().id());

                    //登录成功。
                    sendMessage(new Message(MessageId.SRV_LOGIN_SUCCESS.id, MessageIdTxt.builder().message("").build().toString()));

                    UserDto userDto = new UserDto();
                    BeanUtils.copyProperties(loginUser, userDto);

                    userService.cacheUserLoginServer(getSession().getChannel().id(), userDto);

                    userService.cacheUserDeviceId(loginUser.getUserId(), loginUser.getDeviceId(), currentTimeMillis);

                    //保存和server的关系到redis
                    SessionHolder.addUserSession(userDto, getSession());

                } else {
                    log.error("登陆用户ID[userId={}]，与解密用户ID不一致[userId={}]", loginUser.getUserId(), context.getUserId());
                    sendMessageAndClose(new Message(MessageId.SRV_LOGIN_FAIL.id, MessageIdTxt.builder().message("用户ID违法").build().toString()));
                }

            } else {
                log.warn("登录失败[loginUser=null]");
                sendMessageAndClose(new Message(MessageId.SRV_LOGIN_FAIL.id, MessageTxt.builder().message("解密失败").build().toString()));
            }

        } catch (ExpiredJwtException ex) {
            log.debug("登录失败, to火山九日过期, to火山九日= {}。", loginUser.getTo火山九日(), ex);
            sendMessageAndClose(new Message(MessageId.SRV_LOGIN_FAIL.id, MessageTxt.builder().errCode(ErrorCode.TO火山九日_EXPIRED.getCode()).message(ErrorCode.TO火山九日_EXPIRED.getMsg()).build().toString()));
        } catch (JwtException ex) {
            log.debug("登录失败, to火山九日错误, to火山九日= {}。", loginUser.getTo火山九日(), ex);
            sendMessageAndClose(new Message(MessageId.SRV_LOGIN_FAIL.id, MessageTxt.builder().errCode(ErrorCode.TO火山九日_ERROR.getCode()).message(ErrorCode.TO火山九日_ERROR.getMsg()).build().toString()));
        } catch (Exception e) {
            log.warn("登录失败,to火山九日= {}。", loginUser.getTo火山九日(), e);
            sendMessageAndClose(new Message(MessageId.SRV_LOGIN_FAIL.id, MessageTxt.builder().message("解密失败").build().toString()));
        }

    }

}
